/** @file

Copyright (c) 2006-2023, Kunlun BIOS, Kunlun Technology (Beijing) Co., Ltd.. All
Rights Reserved.

You may not reproduce, distribute, publish, display, perform, modify, adapt,
transmit, broadcast, present, recite, release, license or otherwise exploit
any part of this publication in any form, by any means, without the prior
written permission of Kunlun Technology (Beijing) Co., Ltd..

**/
#include "SetupLibCommon.h"
#include <Protocol/HiiDatabase.h>
#include <Protocol/HiiConfigRouting.h>
#include <Protocol/SetupHiiDataMgr.h>
#include <Protocol/HiiConfigAccess.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Guid/MdeModuleHii.h>
#include <SetupConfig.h>
//add-fc-001-start
#include "Version.h"
#define __INTERNAL_CONVERT_TO_STRING___(a) #a
#define CONVERT_TO_STRING(a) ___INTERNAL_CONVERT_TO_STRING___(a)
//[jckuang-0004]
#include <Library/PcdLib.h>
//[jckuang-0004]
//[zyli-002]-begin
#include <Library/KlCpuAndDdrSettingLib.h>
//[zyli-002]-end
#include "Version.h"

EFI_SMBIOS_HANDLE               gSmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
EFI_SMBIOS_TYPE                 gSmbiosType = SMBIOS_OEM_END;

//add-klk-lyang-P000A-start//
extern UINTN                       TotalMemSize;
extern UINT32                      MemSpeed;
//add-klk-lyang-P000A-end//

CHAR16            *mSetupUnknownString;
EFI_HII_DATABASE_PROTOCOL             *gLibHiiDatabase = NULL;
EFI_HII_CONFIG_ROUTING_PROTOCOL       *gLibHiiConfigRouting = NULL;
STATIC SYSTEM_SETUP_CONFIGURATION            gLibConfiguration;
STATIC SYSTEM_SETUP_CONFIGURATION            gLibConfigurationTmp;
EFI_SMBIOS_PROTOCOL                          *gSmbiosProtocol = NULL;

//SETUP_HII_DATA_MANAGMENT_PROTOCOL            *gSetupDataManagment = NULL;
EFI_GUID  mLibFormSetGuid    = SYSTEM_CONFIGURATION_GUID;
CHAR16    mLibVariableName[] = L"SystemSetupConfig";

EFI_GUID          gSetupLibGuid = { 0x1CCC7C95, 0xD90D, 0x4A5B, { 0xA4, 0xE0, 0xD7, 0x63, 0x76, 0x7B, 0x70, 0x8E } };

EFI_HII_HANDLE    mSetupStringPackHandle;

/**
  Brief description of InitString.

  @param  HiiHandle
  @param  StrRef
  @param  sFormat
  @param  ...

**/
VOID
InitString (
  EFI_HII_HANDLE HiiHandle,
  EFI_STRING_ID StrRef,
  CHAR16 *sFormat,
  ...
  )
{
    CHAR16 s[1024];

    VA_LIST  ArgList;
    VA_START(ArgList, sFormat);
    UnicodeVSPrint(s, sizeof(s), sFormat, ArgList);
    VA_END(ArgList);

    HiiSetString(HiiHandle, StrRef, s, NULL);
}

/**

  Acquire the string associated with the Index from smbios structure and return it.
  The caller is responsible for free the string buffer.

  @param    OptionalStrStart  The start position to search the string
  @param    Index             The index of the string to extract
  @param    String            The string that is extracted

  @retval   EFI_SUCCESS       The function returns EFI_SUCCESS always.

**/
EFI_STATUS
GetOptionalStringByIndex (
  IN      CHAR8                   *OptionalStrStart,
  IN      UINT8                   Index,
  OUT     CHAR16                  **String
  )
{
  UINTN          StrSize;

  if (Index == 0) {
    *String = AllocateZeroPool (sizeof (CHAR16));
    return EFI_SUCCESS;
  }

  StrSize = 0;
  do {
    Index--;
    OptionalStrStart += StrSize;
    StrSize           = AsciiStrSize (OptionalStrStart);
  } while (OptionalStrStart[StrSize] != 0 && Index != 0);

  if ((Index != 0) || (StrSize == 1)) {
    //
    // Meet the end of strings set but Index is non-zero, or
    // Find an empty string
    //
    *String = HiiGetString (SetupLibStrings, STRING_TOKEN (STR_MISSING_STRING), NULL);//GetStringById (STRING_TOKEN (STR_MISSING_STRING));
  } else {
    *String = AllocatePool (StrSize * sizeof (CHAR16));
    AsciiStrToUnicodeStrS (OptionalStrStart, *String, StrSize);
  }

  return EFI_SUCCESS;
}

//add-klk-lyang-P000A-start//
/**
  Brief description of KlGetSmbiosString.

  @param  SmbiosTable
  @param  String

**/
CHAR8 *
KlGetSmbiosString (
  IN VOID                 *SmbiosTable,
  IN SMBIOS_TABLE_STRING  String
  )
{
  CHAR8                   *AString;
  UINT8                   Index;
  EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;

  SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER *)SmbiosTable;
  Index = 1;
  AString = (CHAR8 *)((CHAR8 *)SmbiosTableHeader + SmbiosTableHeader->Length);
  while (Index != String) {
    while (*AString != 0) {
      AString ++;
    }
    AString ++;
    if (*AString == 0) {
      return AString;
    }
    Index ++;
  }

  return AString;
}

/**
  Brief description of CheckSmBiosProtocol.

**/
BOOLEAN
CheckSmBiosProtocol (
  VOID
  )
{
  EFI_STATUS    Status;

  //
  // There should be only one instance in the system
  // of the SetupDataManagment protocol, installed by
  // the BDS before sending the SetupUtilutyBrowser form
  //
  if (gSmbiosProtocol != NULL) {
    return TRUE;
  }
  Status = gBS->LocateProtocol (
                  &gEfiSmbiosProtocolGuid,
                  NULL,
                  (VOID**)&gSmbiosProtocol
                  );

  if (EFI_ERROR (Status)) {
    gSmbiosProtocol = NULL;
    return FALSE;
  }

  return TRUE;
}

//add-klk-lyang-P000A-end//
/**
  Update the information for the Front Page based on SMBIOS information.

  @param  HiiHandle

**/
VOID
UpdateSetupPageStrings (
  IN EFI_HII_HANDLE                         HiiHandle
  )
{
  UINT8                             StrIndex;
  CHAR16                            *NewString;
  EFI_STATUS                        Status;
  EFI_STRING_ID                     TokenToUpdate;
  EFI_SMBIOS_HANDLE                 SmbiosHandle;
//  EFI_SMBIOS_PROTOCOL               *Smbios;
  SMBIOS_TABLE_TYPE0                *Type0Record;
  SMBIOS_TABLE_TYPE2                *Type2Record;
  SMBIOS_TABLE_TYPE1                *Type1Record;
  GUID                              Uuid;
  SMBIOS_TABLE_TYPE4                *Type4Record;
  //SMBIOS_TABLE_TYPE17               *Type17Record = NULL;
  //SMBIOS_TABLE_TYPE19               *Type19Record;
  EFI_SMBIOS_TABLE_HEADER           *Record;
//  UINT64                            MemorySizeMB = 0;
//  UINT64                            MemorySizeGB = 0;
  CHAR16                            StringBuffer[50];
  UINT32                            CpuNum = 0;
//[jckuang-0004]
  UINT16                             version;
//[jckuang-0004]
//
// Update Front Page strings
//
//add-fc-001-start
  UnicodeSPrint(StringBuffer, sizeof(StringBuffer), L"%s", BIOS_GUID);
  DEBUG((EFI_D_INFO,"fanc line:%d guid %s\n", __LINE__, StringBuffer));
  // ZeroMem(BiosString, sizeof(BiosString));
  // StrnCpy(BiosString, BIOS_GUID,23);
   InitString(HiiHandle,
      STRING_TOKEN(STR_BIOS_GUID_VALUE),
      L"%s",
      StringBuffer
      );
//add-fc-001-end
//add-klk-lyang-P000A-start//
  InitString(HiiHandle,
     STRING_TOKEN(STR_BOARD_MEMORY_INFO_VALUE),
     L"%dGB @ %dMHZ",
     TotalMemSize/1024,
     MemSpeed
     );
//add-klk-lyang-P000A-end//

//[jckuang-0004]
  version = PcdGetEx16(&gEfiKunlunBdsPkgTokenSpaceGuid, PcdGetX100Version);
  if (version != 0xFFFF) {
    InitString(HiiHandle,
      STRING_TOKEN(STR_X100_CHIP_VERSION_VALUE),
      L"%d.%d",
      (version >> 4) & 0x0F,
      version & 0x0F
      );
  }
//[jckuang-0004]
  if (CheckSmBiosProtocol()) {
    SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    do {
      Status = gSmbiosProtocol->GetNext (gSmbiosProtocol, &SmbiosHandle, NULL, &Record, NULL);
      if (EFI_ERROR(Status)) {
        break;
      }

      switch (Record->Type) {
      //add for uuid start
      case EFI_SMBIOS_TYPE_SYSTEM_INFORMATION:
        //uuid
        Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
        Uuid = Type1Record->Uuid;
        InitString(HiiHandle,
                   STRING_TOKEN(STR_SYSTEM_UUID_VALUE),
                   L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
                   Uuid.Data1, Uuid.Data2, Uuid.Data3, Uuid.Data4[0], Uuid.Data4[1], Uuid.Data4[2], Uuid.Data4[3], Uuid.Data4[4], Uuid.Data4[5], Uuid.Data4[6], Uuid.Data4[7]
                   );
        //product name
        StrIndex = Type1Record->ProductName;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_SYSTEM_NAME_VALUE);
        HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        //serial number
        StrIndex = Type1Record->SerialNumber;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_SYSTEM_NUMBER_VALUE);
        HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        FreePool (NewString);
      break;
      //add for uuid end
      case EFI_SMBIOS_TYPE_BIOS_INFORMATION:
        Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
   NewString = BIOS_TAG_STR;

        TokenToUpdate = STRING_TOKEN (STR_BIOS_TAG_VALUE);
        //[jdzhang-0003]
        //Modify temporarily, should check why NewString is null
        if(NewString == NULL){
          HiiSetString (HiiHandle, TokenToUpdate, L"BIOS", NULL);
        } else {
          HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        }

        TokenToUpdate = STRING_TOKEN (STR_BIOS_DATE_VALUE);
   NewString = BIOS_BUILD_TIME_STR;
        if(NewString == NULL){
          HiiSetString (HiiHandle, TokenToUpdate, L"Build Time", NULL);
        } else {
          HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        }
        //[jdzhang-0003]
        //EC VERSION
        InitString(HiiHandle,
                   STRING_TOKEN(STR_BOARD_CHIP_EC_REV_VALUE),
                   L"M3PCT%02xAT%02x",
                   Type0Record->EmbeddedControllerFirmwareMajorRelease,
                   Type0Record->EmbeddedControllerFirmwareMinorRelease
                   );

        break;
      case EFI_SMBIOS_TYPE_BASEBOARD_INFORMATION:
        Type2Record = (SMBIOS_TABLE_TYPE2 *) Record;
        //BASEBOARD Product Name
        StrIndex = Type2Record->ProductName;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type2Record + Type2Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_MOTHERBOARD_NAME_VALUE);
        HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        FreePool (NewString);
        //Serial number
        StrIndex = Type2Record->SerialNumber;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type2Record + Type2Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_MOTHERBOARD_NUMBER_VALUE);
        HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        FreePool (NewString);
        //Version
        StrIndex = Type2Record->Version;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type2Record + Type2Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_MOTHERBOARD_VERSION_VALUE);
        HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        FreePool (NewString);
        break;
      //CPU INFORMATION
      case EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION:
        CpuNum ++;
        Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
        //BASEBOARD Product Name
        StrIndex = Type4Record->ProcessorManufacturer;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_BOARD_PROCESSOR_VENDOR_VALUE);
        HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        StrIndex = Type4Record->ProcessorVersion;
        GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
        TokenToUpdate = STRING_TOKEN (STR_BOARD_PROCESSOR_VALUE);
        // HiiSetString (HiiHandle, TokenToUpdate, NewString, NULL);
        InitString(HiiHandle,
           STRING_TOKEN(STR_BOARD_PROCESSOR_VALUE),
                   L"%s @ %dMHz",
                   NewString,
                   Type4Record->CurrentSpeed
                   );
        InitString(HiiHandle,
           STRING_TOKEN(STR_BOARD_PROCESSOR_CORE_VALUE),
                   L"%d Cores * %d",
                   Type4Record->CoreCount,
                   CpuNum
                   );
        if(NewString){
          FreePool (NewString);
        }
        break;

      default:
        break;
      }
    } while (TRUE);
  }
  return ;
}


/**
 Get variable store size in bytes from HII package.

 @param[in]  Package             HII package data
 @param[in]  FormsetGuid         Formset GUID
 @param[in]  VarStoreGuid        Variable store GUID
 @param[in]  VarStoreName        Variable store name
 @param[out] VarStoreSize        Variable store size

 @retval EFI_SUCCESS             Get size successfully
 @retval EFI_INVALID_PARAMETER   Package or FormsetGuid is NULL or it is not form package
 @retval EFI_NOT_FOUND           Form package or variable store is not found
**/
STATIC
EFI_STATUS
GetVarStoreSizeFromPackage (
  IN  UINT8                     *Package,
  IN  EFI_GUID                  *FormsetGuid,
  IN  EFI_GUID                  *VarStoreGuid,
  IN  CHAR8                     *VarStoreName,
  OUT UINT16                    *VarStoreSize
  )
{
  EFI_HII_PACKAGE_HEADER       *PackageHeader;
  UINT32                       Offset;
  EFI_IFR_OP_HEADER            *OpCodeHdr;
  BOOLEAN                      IsCurrentFormset;
  EFI_IFR_VARSTORE             *VarStore;

  if (Package == NULL || FormsetGuid == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  PackageHeader = (EFI_HII_PACKAGE_HEADER *) Package;
  if (PackageHeader->Type != EFI_HII_PACKAGE_FORMS) {
    return EFI_INVALID_PARAMETER;
  }

  IsCurrentFormset = FALSE;
  Offset = sizeof (EFI_HII_PACKAGE_HEADER);
  while (Offset < PackageHeader->Length) {
    OpCodeHdr = (EFI_IFR_OP_HEADER *) (Package + Offset);

    if (OpCodeHdr->OpCode == EFI_IFR_FORM_SET_OP) {
      if (CompareGuid ((EFI_GUID *) (VOID *) (&((EFI_IFR_FORM_SET *) OpCodeHdr)->Guid), FormsetGuid)) {
        IsCurrentFormset = TRUE;
      } else {
        IsCurrentFormset = FALSE;
      }
    }

    if (IsCurrentFormset && OpCodeHdr->OpCode == EFI_IFR_VARSTORE_OP) {
      VarStore = (EFI_IFR_VARSTORE *) OpCodeHdr;

      if (CompareGuid ((EFI_GUID *) (VOID *) (&VarStore->Guid), VarStoreGuid) &&
          AsciiStrCmp ((CHAR8 *) VarStore->Name, VarStoreName) == 0) {
        *VarStoreSize = VarStore->Size;
        return EFI_SUCCESS;
      }
    }

    Offset += OpCodeHdr->Length;
  }

  return EFI_NOT_FOUND;
}

/**
 Get variable store size in bytes.

 @param[in] HiiHandle           An EFI_HII_HANDLE that corresponds to the desired package list in the HII database
 @param[in] FormsetGuid         Formset GUID
 @param[in] VarStoreGuid        Variable store GUID
 @param[in] VarStoreName        Variable store name

 @return The size of variable store in bytes
**/
UINT16
GetVarStoreSize (
  IN EFI_HII_HANDLE            HiiHandle,
  IN EFI_GUID                  *FormsetGuid,
  IN EFI_GUID                  *VarStoreGuid,
  IN CHAR8                     *VarStoreName
  )
{
  EFI_STATUS                   Status;
  EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
  UINTN                        HiiPackageListSize;
  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
  UINT8                        *Package;
  EFI_HII_PACKAGE_HEADER       *PackageHeader;
  UINT32                       Offset;
  UINT32                       PackageListLength;
  UINT16                       VarStoreSize;

  VarStoreSize = 0;

  if (HiiHandle == NULL || FormsetGuid == NULL || VarStoreGuid == NULL || VarStoreName == NULL) {
    return VarStoreSize;
  }

  Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
  if (EFI_ERROR (Status)) {
    return VarStoreSize;
  }

  //
  // Get HII package list
  //
  HiiPackageList     = NULL;
  HiiPackageListSize = 0;
  Status = HiiDatabase->ExportPackageLists (HiiDatabase, HiiHandle, &HiiPackageListSize, HiiPackageList);
  if (Status != EFI_BUFFER_TOO_SMALL) {
    return VarStoreSize;
  }
  HiiPackageList = AllocateZeroPool (HiiPackageListSize);
  if (HiiPackageList == NULL) {
    return VarStoreSize;
  }
  Status = HiiDatabase->ExportPackageLists (HiiDatabase, HiiHandle, &HiiPackageListSize, HiiPackageList);
  if (EFI_ERROR (Status)) {
    FreePool (HiiPackageList);
    return VarStoreSize;
  }

  //
  // In HII package list, find the variable store size which match the formset GUID, variable store GUID and name.
  //
  Offset            = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
  PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
  while (Offset < PackageListLength) {
    Package       = (UINT8 *) HiiPackageList + Offset;
    PackageHeader = (EFI_HII_PACKAGE_HEADER *) Package;

    if (PackageHeader->Type == EFI_HII_PACKAGE_FORMS) {
      Status = GetVarStoreSizeFromPackage (Package, FormsetGuid, VarStoreGuid, VarStoreName, &VarStoreSize);
      if (!EFI_ERROR (Status)) {
        break;
      }
    }

    Offset += PackageHeader->Length;
  }

  FreePool (HiiPackageList);

  return VarStoreSize;
}

/**
  Brief description of SetupGetToken.

  @param  Token
  @param  HiiHandle

**/
CHAR16 *
SetupGetToken (
  IN  EFI_STRING_ID                Token,
  IN  EFI_HII_HANDLE               HiiHandle
  )
{
  EFI_STRING  String;

  String = NULL;//elutang deubg
  String = HiiGetString (HiiHandle, Token, "en-US");
  if (String == NULL) {
    String = AllocateCopyPool (StrSize (mSetupUnknownString), mSetupUnknownString);
  }

  return (CHAR16 *) String;
}

/**
  Brief description of GenericExtractConfig.

  @param  This
  @param  Request
  @param  Progress
  @param  Results

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EFIAPI
GenericExtractConfig (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
  IN  CONST EFI_STRING                       Request,
  OUT EFI_STRING                             *Progress,
  OUT EFI_STRING                             *Results
  )
{
  EFI_STATUS                    Status;
  UINTN                         BufferSize;
  EFI_CALLBACK_INFO             *CallbackInfo;
  EFI_HANDLE                    DriverHandle;
  EFI_GUID                      VarStoreGuid = SYSTEM_CONFIGURATION_GUID;
  UINTN                         Size;
  CHAR16                        *StrPointer;
  EFI_STRING                    ConfigRequestHdr;
  EFI_STRING                    ConfigRequest;
  BOOLEAN                       AllocatedRequest;
//add-klk-lyang-P000A-start//
  VOID*                         VarPtr;
  SYSTEM_ACCESS                 SystemAccess;
  EFI_GUID                      SysAccessGuid = SYSTEM_ACCESS_GUID;
  KUNLUN_HIDE_HOEKEY            HideHotkey;
//add-klk-lyang-P000A-end//
  Status = EFI_SUCCESS;
  if (Progress == NULL || Results == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  BufferSize = sizeof (SYSTEM_SETUP_CONFIGURATION);
  Status = gRT->GetVariable (
                  SETUP_VARIABLE_NAME,
                  &gSystemConfigurationGuid,
                  NULL,
                  &BufferSize,
                  &(gLibConfiguration)
                  );
  if (EFI_ERROR (Status)) {
    return EFI_NOT_FOUND;
  }

//add-klk-lyang-P000A-start//
  VarPtr = &gLibConfiguration;
//add-klk-lyang-P000A-end//
  *Progress = Request;
  CallbackInfo = EFI_CALLBACK_INFO_FROM_THIS (This);
  BufferSize       = GetVarStoreSize (CallbackInfo->HiiHandle, &CallbackInfo->FormsetGuid, &VarStoreGuid, "SystemSetupConfig");


  ConfigRequestHdr = NULL;
  ConfigRequest    = NULL;
  AllocatedRequest = FALSE;
  ConfigRequest = Request;
  if (Request == NULL) {
    //
    // Request is set to NULL, construct full request string.
    //
    //
    // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
    // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
    //
    Status = gLibHiiDatabase->GetPackageListHandle (gLibHiiDatabase, CallbackInfo->HiiHandle, &DriverHandle);
    if (EFI_ERROR (Status)) {
      return EFI_NOT_FOUND;
    }
    ConfigRequestHdr = HiiConstructConfigHdr (&mLibFormSetGuid, mLibVariableName, DriverHandle);
    if (ConfigRequestHdr == NULL) return EFI_NOT_FOUND;
    Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
//add-klk-lyang-P000A-start//
    ConfigRequest = AllocateZeroPool (Size);
//add-klk-lyang-P000A-end//
    if (ConfigRequest == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    AllocatedRequest = TRUE;
    UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64) BufferSize);
    FreePool (ConfigRequestHdr);
    ConfigRequestHdr = NULL;

  } else {
    //
    // Check routing data in <ConfigHdr>.
    // Note: if only one Storage is used, then this checking could be skipped.
    //
    if (!HiiIsConfigHdrMatch (Request, &mLibFormSetGuid, mLibVariableName)) {
//add-klk-lyang-P000A-start//
      if(!HiiIsConfigHdrMatch (Request, &SysAccessGuid, L"SystemAccess")){
        if (!HiiIsConfigHdrMatch (Request, &gKunlunHideHotkeyGuid, L"KunlunHideHotkey")) {
          return EFI_NOT_FOUND;
        } else {
          BufferSize = sizeof (KUNLUN_HIDE_HOEKEY);
          Status = gRT->GetVariable (
                          L"KunlunHideHotkey",
                          &gKunlunHideHotkeyGuid,
                          NULL,
                          &BufferSize,
                          &(HideHotkey)
                          );
          if (EFI_ERROR (Status)) {
            return EFI_NOT_FOUND;
          }
          VarPtr = &HideHotkey;
        }
      } else {
        BufferSize = sizeof (SYSTEM_ACCESS);
        Status = gRT->GetVariable (
                        L"SystemAccess",
                        &SysAccessGuid,
                        NULL,
                        &BufferSize,
                        &(SystemAccess)
                        );
        if (EFI_ERROR (Status)) {
          return EFI_NOT_FOUND;
        }
        VarPtr = &SystemAccess;
      }
//add-klk-lyang-P000A-end//
    }
    //
    // Check whether Request includes Request Element.
    //
    if (StrStr (Request, L"OFFSET") == NULL) {
      //
      // Check Request Element does exist in Reques String
      //
      StrPointer = StrStr (Request, L"PATH");
      if (StrPointer == NULL) {
        return EFI_INVALID_PARAMETER;
      }
      if (StrStr (StrPointer, L"&") == NULL) {
        Size = (StrLen (Request) + 32 + 1) * sizeof (CHAR16);
        ConfigRequest = AllocateZeroPool (Size);
        if (ConfigRequest == NULL) {
          return EFI_OUT_OF_RESOURCES;
        }
//        ASSERT (ConfigRequest != NULL);
        AllocatedRequest = TRUE;
        UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", Request, (UINT64) BufferSize);
      }
    }
  }
  if (StrStr (ConfigRequest, L"OFFSET") == NULL) {
    //
    // If requesting Name/Value storage, return not found.
    //
    return EFI_NOT_FOUND;
  }
  //
  // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
  //
  Status = gLibHiiConfigRouting->BlockToConfig (
                                   gLibHiiConfigRouting,
                                   ConfigRequest,
                                   (UINT8 *)VarPtr,
                                   BufferSize,
                                   Results,
                                   Progress
                                   );

  //
  // Free the allocated config request string.
  //
  if (AllocatedRequest) {
    gBS->FreePool (ConfigRequest);
    ConfigRequest = NULL;
  }
  //
  // Set Progress string to the original request string.
  //
  if (Request == NULL) {
    *Progress = NULL;
  } else if (StrStr (Request, L"OFFSET") == NULL) {
    *Progress = Request + StrLen (Request);
  }

  return Status;
}


/**
  Brief description of GenericRouteConfig.

  @param  This
  @param  Configuration
  @param  Progress

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EFIAPI
GenericRouteConfig (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
  IN  CONST EFI_STRING                       Configuration,
  OUT EFI_STRING                             *Progress
  )
{
  EFI_STATUS                                Status;
  UINTN                                     BufferSize;
 //add-klk-lyang-P000A-start//
  VOID                          *VarPtr;
  SYSTEM_ACCESS                 SystemAccess;
  EFI_GUID                      SysAccessGuid = SYSTEM_ACCESS_GUID;
  EFI_GUID                      *GuidPtr;
  CHAR16                        *VarName;
  UINTN                         StoreBufferSize;
//add-klk-lyang-P000A-end//

  GuidPtr = NULL;
  VarName = NULL;
  if (Configuration == NULL || Progress == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  *Progress = Configuration;

  //
  // Get Buffer Storage data from EFI variable
  //
  BufferSize = sizeof (SYSTEM_SETUP_CONFIGURATION);
  Status = gRT->GetVariable (
                  SETUP_VARIABLE_NAME,
                  &gSystemConfigurationGuid,
                  NULL,
                  &BufferSize,
                  &gLibConfiguration
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  gLibConfigurationTmp = gLibConfiguration;
//add-klk-lyang-P000A-start//
  VarPtr = &gLibConfiguration;
  GuidPtr = &gSystemConfigurationGuid;
  VarName = SETUP_VARIABLE_NAME;
//add-klk-lyang-P000A-end//
  if (!HiiIsConfigHdrMatch (Configuration, &gSystemConfigurationGuid, mLibVariableName)) {
     //add-klk-lyang-P000A-start//
     if(!HiiIsConfigHdrMatch (Configuration, &SysAccessGuid, L"SystemAccess")){
//[-start-klk-lyang-010-20221202-add]//
       if (HiiIsConfigHdrMatch (Configuration, &gKunlunHideHotkeyGuid, L"KunlunHideHotkey")) {
         return EFI_SUCCESS;
       }
//[-end-klk-lyang-010-20221202-add]//
       return EFI_NOT_FOUND;
     } else {
       BufferSize = sizeof (SYSTEM_ACCESS);
       Status = gRT->GetVariable (
                       L"SystemAccess",
                       &SysAccessGuid,
                       NULL,
                       &BufferSize,
                       &(SystemAccess)
                       );
       if (EFI_ERROR (Status)) {
         return EFI_NOT_FOUND;
       }
       VarPtr = &SystemAccess;
       VarName = L"SystemAccess";
       GuidPtr = &SysAccessGuid;
     }
 //add-klk-lyang-P000A-end//
   }

  //
  // Check if configuring Name/Value storage
  //
  if (StrStr (Configuration, L"OFFSET") == NULL) {
     return EFI_SUCCESS;
  }
//add-klk-lyang-P000A-start//
  StoreBufferSize = BufferSize;
//add-klk-lyang-P000A-end//
  // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
  //
  Status = gLibHiiConfigRouting->ConfigToBlock (
                                   gLibHiiConfigRouting,
                                   Configuration,
                                   (UINT8 *) VarPtr,
                                   &BufferSize,
                                   Progress
                                   );
  if (EFI_ERROR (Status)) {
    return Status;
  }
   //[zhyli-0002]-add-begin
   if(FixedPcdGet32(PcdTheCpuType) == 0){
    KlCpuAndDdrSettingInit();
   }
   //[zhyli-0002]-add-end
  //
  // Store Buffer Storage back to EFI variable
  //
  Status = gRT->SetVariable(
                  VarName,
                  GuidPtr,
                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
                  StoreBufferSize,
                  VarPtr
                  );
  return Status;
}

/**
  According platform setting to configure setup variable

  @param  VariableGuid           An optional field to indicate the target variable GUID name to use.
  @param  VariableName           An optional field to indicate the target human-readable variable name.
  @param  BufferSize             On input: Length in bytes of buffer to hold retrived data.
                                 On output:
                                   If return EFI_BUFFER_TOO_SMALL, containg length of buffer desired.
  @param  Buffer                 Buffer to hold retrived data.
  @param  RetrieveData           TRUE : Get setup variable from broswer
                                 FALSE: Set current setuputility setting to browser

  @retval EFI_SUCCESS            Setup variable configuration successful
  @retval EFI_ABORTED            Setup variable configuration failed

**/
EFI_STATUS
SetupVariableConfig (
  IN EFI_GUID        *VariableGuid, OPTIONAL
  IN CHAR16          *VariableName, OPTIONAL
  IN UINTN           BufferSize,
  IN UINT8           *Buffer,
  IN BOOLEAN         RetrieveData
  )
{
  BOOLEAN            Success;

  if (RetrieveData) {
    Success = HiiGetBrowserData (VariableGuid, VariableName, BufferSize, Buffer);
  } else {
    Success = HiiSetBrowserData (VariableGuid, VariableName, BufferSize, Buffer, NULL);
  }
  if (!Success) {
    ;
  }

  return Success ? EFI_SUCCESS : EFI_ABORTED;
}


/**
  Brief description of SetupSetConsoleMode.

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
SetupSetConsoleMode (
  VOID
  )
{
  EFI_STATUS                            Status;
  EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
  UINT32                                MaxGopMode;
  UINT32                                MaxTextMode;
  UINT32                                ModeNumber;
  UINTN                                 SizeOfInfo;
  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
  UINT32                                NewHorizontalResolution;
  UINT32                                NewVerticalResolution;
  UINT32                                NewColumns;
  UINT32                                NewRows;
  UINTN                                 Index;
  UINTN                                 CurrentColumn;
  UINTN                                 CurrentRow;
  BOOLEAN                               FoundTextMode;

  MaxGopMode  = 0;
  MaxTextMode = 0;
  FoundTextMode = FALSE;
  Info = NULL;
  //
  // Get current video resolution and text mode
  //
  Status = gBS->HandleProtocol (
                  gST->ConsoleOutHandle,
                  &gEfiGraphicsOutputProtocolGuid,
                  (VOID**)&GraphicsOutput
                  );

  if (EFI_ERROR (Status)) {
    GraphicsOutput = NULL;
  }
  Status = gBS->HandleProtocol (
                  gST->ConsoleOutHandle,
                  &gEfiSimpleTextOutProtocolGuid,
                  (VOID**)&SimpleTextOut
                  );
  if (EFI_ERROR (Status)) {
    SimpleTextOut = NULL;
  }
#if 0

#else
  //[jckuang-0002]
  //if No VGA output, the console will not be set,
  //the console redirection setup output will cause garbage characters.
  if ((GraphicsOutput == NULL) && (SimpleTextOut == NULL)) {
    DEBUG ((EFI_D_ERROR, "TANG: NO GOP\n"));
    return EFI_UNSUPPORTED;
  }
  //[gliu-0006]
  NewHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
  NewVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
  NewColumns = NewHorizontalResolution / EFI_GLYPH_WIDTH;
  NewRows   = NewVerticalResolution / EFI_GLYPH_HEIGHT;
  //[gliu-0006]
  if (GraphicsOutput != NULL) {
  //[gliu-0006]
  /*NewHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
    NewVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
    NewColumns = NewHorizontalResolution / EFI_GLYPH_WIDTH;
    NewRows   = NewVerticalResolution / EFI_GLYPH_HEIGHT;*/
  //[gliu-0006]
    MaxGopMode  = GraphicsOutput->Mode->MaxMode;
    DEBUG ((EFI_D_INFO, "Graphics Output init\n"));
    //
    //Setup GOP mode for setup
    //
    if ((GraphicsOutput->Mode->Info->HorizontalResolution != NewHorizontalResolution) ||
    (GraphicsOutput->Mode->Info->VerticalResolution != NewVerticalResolution)) {

      for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
        Status = GraphicsOutput->QueryMode (
                                  GraphicsOutput,
                                  ModeNumber,
                                  &SizeOfInfo,
                                  &Info
                                  );
        if (!EFI_ERROR (Status)) {
          if ((Info->HorizontalResolution == NewHorizontalResolution) &&
            (Info->VerticalResolution == NewVerticalResolution)) {
        Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
        break;
        }
        }
      }
    }
  }

  //
  //Setup test mode for setup
  //
  if (SimpleTextOut != NULL) {
    MaxTextMode = SimpleTextOut->Mode->MaxMode;
    Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
    if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
    //
    // If current text mode is same with required text mode. Do nothing
    //
    FoundTextMode = TRUE;
    } else {
      for (Index = 0; Index < MaxTextMode; Index++) {
        Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
        if (!EFI_ERROR(Status)) {
          if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
          //
          // Required text mode is supported, set it.
          //
          Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
          FoundTextMode = TRUE;
          }
        }
      }
    }
    Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, (UINTN*)&NewColumns, &CurrentRow);
    if(EFI_ERROR(Status)){
      NewColumns = (FoundTextMode? NewColumns : 100);
    }
    DEBUG ((EFI_D_INFO, "Simple TextOut column=%d, row=%d----\n", NewColumns, CurrentRow));
    PcdSetEx32S (&gEfiKunlunBdsPkgTokenSpaceGuid, PcdSetupLayoutMenuOptionWidth, NewColumns / 3 -1);
    PcdSetEx32S (&gEfiKunlunBdsPkgTokenSpaceGuid, PcdSetupLayoutMenuOptionPromptWidth, NewColumns / 3 -1);
    PcdSetEx32S (&gEfiKunlunBdsPkgTokenSpaceGuid, PcdSetupLayoutHelpWidth,
    NewColumns-PcdGet32(PcdSetupLayoutMenuOptionWidth) - PcdGet32(PcdSetupLayoutMenuOptionPromptWidth) -1 - 1 -1 -1);
  }
  //[jckuang-0002]
#endif
  //DEBUG ((EFI_D_ERROR, "PcdSetupLayoutHelpWidth %d\n",PcdGet32(PcdSetupLayoutHelpWidth)));
  if (Info != NULL) {
    FreePool (Info);
  }
  //DEBUG ((EFI_D_ERROR, "PcdSetupLayoutHelpWidth %d\n",PcdGet32(PcdSetupLayoutMenuOptionPromptWidth)));
  return EFI_SUCCESS;
}

/**
  Brief description of SetupLibConstructor.

  @param  ImageHandle
  @param  SystemTable

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EFIAPI
SetupLibConstructor (
  IN      EFI_HANDLE                ImageHandle,
  IN      EFI_SYSTEM_TABLE          *SystemTable
  )
{
  EFI_STATUS     Status;

  CheckSetupHiiDataManager();

  mSetupStringPackHandle = HiiAddPackages (&gSetupLibGuid, ImageHandle, SetupLibStrings, NULL);


  Status = gBS->LocateProtocol (
                  &gEfiHiiDatabaseProtocolGuid,
                  NULL,
                  (VOID **)&gLibHiiDatabase
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // There should only be one HII protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiHiiConfigRoutingProtocolGuid,
                  NULL,
                  (VOID **)&gLibHiiConfigRouting
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  return EFI_SUCCESS;
}

/**
  Brief description of SetupLibDestructor.

  @param  ImageHandle
  @param  SystemTable

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EFIAPI
SetupLibDestructor (
  IN      EFI_HANDLE                ImageHandle,
  IN      EFI_SYSTEM_TABLE          *SystemTable
  )
{


  return EFI_SUCCESS;
}
